
%{
#include "parser_state.hpp"
#include "parser.hpp"
%}

%option yylineno
%option noyywrap
%option reentrant stack

nondigit	[a-zA-Z_]
digit		[0-9]
identifier 	{nondigit}({digit}|{nondigit})*
double		({digit}+\.{digit}*)|({digit}*\.{digit}+)([Ee][+-]?[0-9]+)
integer		([1-9][0-9]*)|(0[0-7]*)|(0[xX][0-9a-fA-F]+)
escape_seq	"\\"([\'\"?\\abfnrtv]|[0-7]{1,3}|[xX][0-9a-fA-F]+)
character	L?'([^'\\\n]|{escape_seq})'
comment		("//"[^\n]*\n)|("/*"([^*]|\*[^/])*"*/")
include		#include[ \t]+((\"[^\"\r\n]+\")|(<[^>\r\n]+>))[ \t]*\n
schar		[^\"\\\n]|{escape_seq}
string		(\"{schar}*\"[ \r\n\t]*)+|(L\"{schar}*\"[ \r\n\t]*)+

%%

{comment}

{double}	return TOK_double;
{integer}	return TOK_integer;
{character}	return TOK_character;
{string}	return TOK_string;

#include[ \t]+<cppscript>[ \t]*\n 	return TOK_cppscript_include;
{include}	return TOK_other_include;

"{"		return '{';
"}"		return '}';
"["		return '[';
"]"		return ']';
"#"		return TOK_error;
"##"		return TOK_error;
"("		return '(';
")"		return ')';
"<:"		return TOK_reserved_keyword;
":>"		return TOK_reserved_keyword;
"<%"		return TOK_reserved_keyword;
"%>"		return TOK_reserved_keyword;
"%:%:"		return TOK_reserved_keyword;
"%:"		return TOK_reserved_keyword;
";"		return ';';
":"		return ':';
"?"		return '?';
"::"		return TOK_coloncolon;
"."		return '.';
".*"		return TOK_error;
"+"		return '+';
"-"		return '-';
"*"		return '*';
"/"		return '/';
"%"		return '%';
"^"		return '^';
"&"		return '&';
"|"		return '|';
"~"		return '~';
"!"		return '!';
"="		return '=';
"<"		return '<';
">"		return '>';
"+="		return TOK_add_eq;
"-="		return TOK_sub_eq;
"*="		return TOK_mul_eq;
"/="		return TOK_div_eq;
"%="		return TOK_mod_eq;
"^="		return TOK_xor_eq;
"&="		return TOK_and_eq;
"|="		return TOK_or_eq;
"<<="		return TOK_left_eq;
">>="		return TOK_right_eq;
"<<"		return TOK_left;
">>"		return TOK_right;
"=="		return TOK_eq;
"!="		return TOK_neq;
"<="		return TOK_leq;
">="		return TOK_geq;
"&&"		return TOK_and;
"||"		return TOK_or;
"++"		return TOK_plusplus;
"--"		return TOK_minusminus;
","		return ',';
"->"		return TOK_error;
"->*"		return TOK_error;
"..."		return TOK_error;

and		return TOK_reserved_keyword;
and_eq		return TOK_reserved_keyword;
asm		return TOK_reserved_keyword;
auto		return TOK_reserved_keyword;
bitand		return TOK_reserved_keyword;
bitor		return TOK_reserved_keyword;
bool		return TOK_reserved_keyword;
break		return TOK_break;
case		return TOK_case;
catch		return TOK_catch;
char		return TOK_reserved_keyword;
class		return TOK_reserved_keyword;
compl		return TOK_reserved_keyword;
const		return TOK_reserved_keyword;
const_cast	return TOK_reserved_keyword;
continue	return TOK_continue;
default		return TOK_default;
delete		return TOK_reserved_keyword;
do		return TOK_do;
double		return TOK_reserved_keyword;
dynamic_cast	return TOK_reserved_keyword;
else		return TOK_else;
enable_pickle	return TOK_enable_pickle;
enum		return TOK_reserved_keyword;
explicit	return TOK_reserved_keyword;
export		return TOK_reserved_keyword;
extern		return TOK_reserved_keyword;
false		return TOK_false;
finally		return TOK_finally;
float		return TOK_reserved_keyword;
for		return TOK_for;
foreach		return TOK_foreach;
friend		return TOK_reserved_keyword;
goto		return TOK_goto;
if		return TOK_if;
inline		return TOK_reserved_keyword;
int		return TOK_reserved_keyword;
long		return TOK_reserved_keyword;
mutable		return TOK_reserved_keyword;
namespace	return TOK_namespace;
new		return TOK_reserved_keyword;
not		return TOK_reserved_keyword;
not_eq		return TOK_reserved_keyword;
null		return TOK_null;
operator	return TOK_reserved_keyword;
or		return TOK_reserved_keyword;
or_eq		return TOK_reserved_keyword;
private		return TOK_reserved_keyword;
protected	return TOK_reserved_keyword;
public		return TOK_reserved_keyword;
register	return TOK_reserved_keyword;
reinterpret_cast return TOK_reserved_keyword;
return		return TOK_return;
script_main	return TOK_script_main;
short		return TOK_reserved_keyword;
signed		return TOK_reserved_keyword;
sizeof		return TOK_reserved_keyword;
static		return TOK_reserved_keyword;
static_cast	return TOK_reserved_keyword;
struct		return TOK_reserved_keyword;
switch		return TOK_switch;
template	return TOK_reserved_keyword;
this		return TOK_reserved_keyword;
throw		return TOK_throw;
true		return TOK_true;
try		return TOK_try;
typedef		return TOK_reserved_keyword;
typeid		return TOK_reserved_keyword;
typename	return TOK_reserved_keyword;
union		return TOK_reserved_keyword;
unsigned	return TOK_reserved_keyword;
using		return TOK_using;
virtual		return TOK_reserved_keyword;
void		return TOK_void;
volatile	return TOK_reserved_keyword;
wchar_t		return TOK_reserved_keyword;
while		return TOK_while;
xor		return TOK_reserved_keyword;
xor_eq		return TOK_reserved_keyword;
var		return TOK_var;
{identifier}  return TOK_identifier;
[ \r\n\t]+
.		return TOK_error;

%% 

int yylex( var * result, parser_state & ps )
{
	int r = yylex(ps.scanner_state);
	
	switch(r)
	{
	case TOK_double:
		*result = parse_double(yyget_text(ps.scanner_state));
		break;
	case TOK_integer:
		*result = parse_integer(yyget_text(ps.scanner_state));
		break;
	case TOK_character:
		*result = parse_char(yyget_text(ps.scanner_state));
		break;
	case TOK_string:
		*result = parse_string_token(yyget_text(ps.scanner_state));
		break;
	case TOK_script_main:
	case TOK_identifier:
	case TOK_other_include:
		*result = yyget_text(ps.scanner_state);
		break;
	default:
		*result = null;
	}
	return r;
}


var dynamic::parse_file(var filename)
{
	parser_state ps;

	FILE * file = fopen(filename.as_string().c_str(), "r");

	if(!file) throw exception("file_open", "Could not open the file", filename);
	yyset_in( file, ps.scanner_state );

	try
	{
		if( yyparse(ps) )
		{
			ps.error_syntax_error();
		}
		else
		{
			fclose(file);
			return ps.parse_result;
		}
	}
	catch(...)
	{
		fclose(file);
		throw;
	}
}


var dynamic::parse_string(var string)
{
	parser_state ps;

	std::string str = string.as_string();
	YY_BUFFER_STATE buffer = yy_scan_bytes(str.c_str(), str.size(), ps.scanner_state);
	yy_switch_to_buffer(buffer, ps.scanner_state);
	yyset_lineno(1, ps.scanner_state);

	try
	{
		if( yyparse(ps) )
		{
			ps.error_syntax_error();
		}
		else
		{
			yy_delete_buffer(buffer, ps.scanner_state);
			return ps.parse_result;
		}
	}
	catch(...)
	{
		yy_delete_buffer(buffer, ps.scanner_state);
		throw;
	}
}


parser_state::parser_state()
{
	yylex_init(&scanner_state);
	global_namespace = create_namespace();
	current_namespace = global_namespace;

	declare_library_function("writeln", writeln);
}


parser_state::~parser_state()
{
	yylex_destroy(scanner_state);
}


void parser_state::error(const char * type, var text)
{
	throw exception(type, text, yyget_lineno(scanner_state));
}
